/**
在 Webpack 中，自定义分包（Custom Code Splitting）是一种灵活的代码分割策略，允许开发者根据特定需求和逻辑自定义如何将代码拆分成多个包。通过自定义分包，开发者可以更好地控制应用的性能和加载行为。
  1. 什么是自定义分包？
  自定义分包是指开发者根据业务需求和代码结构，灵活地定义如何将应用的代码拆分成多个部分。与默认的分包策略不同，自定义分包允许开发者指定哪些模块应该被打包到一起，哪些模块应该单独打包。

  2. 自定义分包的优势
  - 优化加载性能: 根据用户的使用习惯和访问路径，定制加载的模块，从而提升性能。
  - 减少初始加载时间: 通过将较大或不常用的模块拆分出来，降低初始加载时的资源消耗。
  - 灵活性: 开发者可以根据具体的业务逻辑和需求进行更细粒度的控制。

  3. 自定义分包的实现方式

   1. 使用 `SplitChunksPlugin`
  Webpack 提供了 `SplitChunksPlugin`，可以通过配置来实现自定义分包。以下是一些常用的配置选项：

  - minSize: 指定生成的代码块的最小大小，低于该大小的块将被合并。
  - maxSize: 指定生成的代码块的最大大小，超过该大小的块将被拆分。
  - minChunks: 指定一个模块被引用的最小次数，只有当模块被引用的次数达到这个值时，才会被提取到公共代码块中。
  - automaticNameDelimiter: 设置生成名称时的分隔符。
   示例配置：

  module.exports = {
      // ...
      optimization: {
          splitChunks: {
              chunks: 'all', // 对所有类型的块进行分割
              minSize: 20000, // 最小为 20KB
              maxSize: 40000, // 最大为 40KB
              minChunks: 1, // 最小引用次数
              maxAsyncRequests: 30, // 最大异步请求数
              maxInitialRequests: 30, // 最大初始请求数
              automaticNameDelimiter: '~', // 生成名称时的分隔符
              cacheGroups: {
                  vendor: {
                      test: /[\\/]node_modules[\\/]/, // 匹配 node_modules
                      name: 'vendors', // 生成的名称
                      chunks: 'all',
                  },
                  default: {
                      minChunks: 2, // 至少被引用两次的模块
                      priority: -20, // 优先级
                      reuseExistingChunk: true, // 重用已有的块
                  },
              },
          },
      },
  };

   2. 使用动态导入
  通过动态导入，开发者可以在代码中指定某些模块的加载条件，从而实现自定义分包。例如，可以根据用户的操作或页面的路由动态加载特定的模块。

  ```javascript
  // 在用户点击按钮时动态加载模块
  document.getElementById('loadButton').addEventListener('click', () => {
      import('./moduleA')
          .then(module => {
              module.default(); // 调用加载的模块
          })
          .catch(err => {
              console.error('模块加载失败:', err);
          });
  });
  ```

  4. 注意事项
  - 性能平衡: 自定义分包可以提升性能，但过度拆分可能导致请求数量增加，反而影响性能。因此，需要在分包和请求数量之间找到平衡。
  - 模块依赖: 在自定义分包时，要考虑模块间的依赖关系，确保模块能够正常加载和运行。
  - 测试: 在实施自定义分包策略后，进行充分的测试以确保应用的稳定性和性能。

  总结
  Webpack 的自定义分包功能为开发者提供了灵活的代码分割策略，可以根据具体业务需求优化应用的加载性能。通过合理配置 `SplitChunksPlugin` 和使用动态导入，开发者可以有效地管理代码的加载和执行，提高用户体验。希望这个总结对你理解 Webpack 中的自定义分包有所帮助！
 */
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const TerserPlugin = require("terser-webpack-plugin");

module.exports = {
  mode: "production",
  devtool: false,
  entry: "./src/main.js",
  output: {
    clean: false,
    path: path.resolve(__dirname, "./build"),
    filename: "[name]-bundle.js",
    chunkFilename: "[name]_chunk.js",
  },
  resolve: {
    extensions: [".js", ".json", ".wasm", ".ts", ".jsx"],
  },
  devServer: {
    static: ["public", "content"], // 配置静态资源目录
    port: 3000,
    compress: true,
    proxy: [
      {
        context: "/api",
        target: "http://localhost:4000",
        pathRewrite: { "^/api": "" },
        changeOrigin: true,
      },
    ],
    historyApiFallback: true, // 解决单页面应用刷新404问题
  },
  /**
   * optimization: 优化配置
   * 1. 代码分割
   * 2. 压缩
   * 3. Tree Shaking: 摇树优化
   * 4. Scope Hoisting: 作用域提升
   * 5. 代码分割动态导入
   * 6. SplitChunksPlugin: webpack内置的代码分割插件
   * 7. 内联chunk: runtime相关的代码内联到html中
   * 8. runtimeChunk: runtime相关的代码单独打包
   * 9. DllPlugin: 动态链接库插件
   */
  optimization: {
    /**
     * chunkIds: 代码分割的chunk命名方式
     * 1. natural => webpack4中使用: 自然数
     * 2. named => development环境: 文件名
     * 3. deterministic => production环境: 确定性命名
     */
    chunkIds: "deterministic",
    /**
     * runtimeChunk: runtime相关的代码单独打包
     * 1. single => 单独打包一个runtime文件
     * 2. multiple => 每个入口文件单独打包一个runtime文件
     * 3. true => 自动选择
     * 4. false => 不单独打包runtime文件
     * 5. name => 自定义runtime文件名
     * 6. object => 自定义runtime文件名
     */
    runtimeChunk: {
      name: "runtime",
    },
    /**
     * splitChunks: 代码分割配置
     */
    splitChunks: {
      /**
       * chunks: 代码分割的范围
       * 1. all => 所有模块
       * 2. async => 异步模块
       * 3. initial => 同步模块
       */
      chunks: "all",
      /**
       * minSize: 代码分割的最小大小
       * 1. 20000 => 20kb
       * 2. 200 => 200字节
       */
      minSize: 10,
      /**
       * maxSize: 代码分割的最大大小
       * 1. 20000 => 20kb
       * 2. 200 => 200字节
       **/
      // maxSize: 0,
      /**
       * cacheGroups: 代码分割的缓存组
       * 1. vendors => 第三方模块
       * 2. default => 默认的缓存组
       * 3. utils => 自定义的缓存组
       */
      cacheGroups: {
        utils: {
          test: /utils/,
          filename: "[id]_utils.js",
        },
        vendors: {
          test: /[\\/]node_modules[\\/]/,
          filename: "[id]_vendors.js",
        },
      },
    },
    /**
     * minimizer: 代码优化配置
     * 1. TerserPlugin => 让代码更加简单 => Terser
     * 2. OptimizeCSSAssetsPlugin => 压缩css
     * 3. CompressionWebpackPlugin => 压缩文件
     * 4. ImageMinimizerPlugin => 压缩图片
     */
    minimizer: [
      // JS代码优化: TerserPlugin => 让代码更加简单 => Terser
      new TerserPlugin({
        extractComments: false, // 不将注释提取到单独的文件中
      }),
    ],
  },
  module: {
    rules: [
      {
        test: /\.jsx?$/,
        use: {
          loader: "babel-loader",
        },
      },
      {
        test: /\.ts$/,
        use: "babel-loader",
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: "./index.html",
    }),
  ],
};
